package com.bauer.base.thread;

import com.bauer.base.concurrent.ThreadPoolUtil;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;

public class Counter {


    private int i = 0;

    private static int normalAdder = 0;

    private volatile static int volatileAdder = 0;

    private static AtomicInteger atomicInteger = new AtomicInteger(0);

    private static LongAdder longAdder = new LongAdder();

    private Mylock mylock = new Mylock();

    private MyReenTrantLock myReenTrantLock = new MyReenTrantLock();

    /**
     * normalAdd  volatileAdd 是线程不安全的
     * atomicAdd  longAdder 线程安全的   但是longadder的耗时要低很多
     * @param args
     */
    public static void main(String[] args) {
//        normalAdd();
        volatileAdd();
//        atomicAdd();
//        longAdder();

    }


    public static void atomicAdd() {
        long statTime = System.currentTimeMillis();

        Runnable volatileDemo = () -> {
            for (int i = 0; i < 10000; i++) {
                atomicInteger.incrementAndGet();
            }
        };
        ThreadPoolUtil.executeTimes(volatileDemo, 100, () -> {
            long costTime = System.currentTimeMillis() - statTime;
            System.out.println(atomicInteger.get());
            System.out.println("total use time :{" + costTime + "}");
        });
    }

    public static void longAdder() {
        long statTime = System.currentTimeMillis();

        Runnable volatileDemo = () -> {
            for (int i = 0; i < 10000; i++) {
                longAdder.increment();
            }
        };
        ThreadPoolUtil.executeTimes(volatileDemo, 10, () -> {
            long costTime = System.currentTimeMillis() - statTime;
            System.out.println(longAdder.intValue());
            System.out.println("total use time :{" + costTime + "}");
        });
    }

    public static void volatileAdd() {
        long statTime = System.currentTimeMillis();

        Runnable volatileDemo = () -> {
            for (int i = 0; i < 10000; i++) {
                volatileAdder++;
            }
        };
        ThreadPoolUtil.executeTimes(volatileDemo, 10, () -> {
            long costTime = System.currentTimeMillis() - statTime;
            System.out.println(volatileAdder);
            System.out.println("total use time :{" + costTime + "}");
        });
    }

    public static void normalAdd() {
        long statTime = System.currentTimeMillis();

        Runnable volatileDemo = () -> {
            for (int i = 0; i < 10000; i++) {
                normalAdder++;
            }
        };
        ThreadPoolUtil.executeTimes(volatileDemo, 10, () -> {
            long costTime = System.currentTimeMillis() - statTime;
            System.out.println(normalAdder);
            System.out.println("total use time :{" + costTime + "}");
        });
    }

    public int add(int value) {
        this.i = this.i + value;
        try {
            /**
             * 为了使现象明显 增加了延时操作
             */
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return this.i;
    }

    /**
     * 通过加synchronized实现 线程安全
     */
    public synchronized int addSafe(int value) {
        this.i = this.i + value;
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return i;
    }

    /**
     * 通过加synchronized实现 线程安全
     */
    public int addSafeBuyMulock(int value) throws Exception {
        mylock.lock();
        this.i = this.i + value;
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        mylock.unlock();
        return i;
    }


    /**
     * 可重入锁
     */
    public int addSafeBuyMyReenTrantLock(int value) throws Exception {
        myReenTrantLock.lock();
        this.i = this.i + value;
        lockAgain();
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        myReenTrantLock.unlock();
        return i;
    }

    public void lockAgain() throws Exception {
        myReenTrantLock.lock();
        myReenTrantLock.unlock();
    }


    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }
}
